package com.my.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.my.domain.ParkingSpace;
import com.my.domain.Result;
import com.my.mapper.ParkingSpaceMapper;
import com.my.service.ParkingSpaceService;
import com.my.websocket.WebSocketClients;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import java.util.*;

@Service
public class ParkingSpaceServiceImpl implements ParkingSpaceService {

    @Autowired
    private Timer timer;

    @Resource
    private Map<Integer, TimerTask> timerTaskMap;//存预定车位的定时任务

    @Resource
    private Map<Integer, TimerTask> timerTask2Map;//存预定车位的定时任务

    @Resource
    private Map<Integer, HttpSession> sessionMap;//存预定车位的客户端session

    @Autowired
    private ParkingSpaceMapper parkingSpaceMapper;

    @Autowired
    private ObjectMapper objectMapper;

    //----以下是实现的业务方法，除了getCost外都会被AOP增强-----//

    @Override
    public ParkingSpace findById(Integer id) {
        return parkingSpaceMapper.findById(id);
    }

    @Override
    public List<ParkingSpace> findAll() {
        return parkingSpaceMapper.findAll();
    }

    @Override
    public ParkingSpace findOneFree() {
        return parkingSpaceMapper.findOneFree();
    }

    @Override
    public Result parking(Integer id) {
        if (timerTask2Map.containsKey(id)) {
            TimerTask timerTask = timerTask2Map.remove(id);//解除预定车位冷却的定时任务
            timerTask.cancel();
        }

        ParkingSpace parkingSpace = new ParkingSpace();
        parkingSpace.setId(id);
        parkingSpace.setLocked(true);
        parkingSpace.setStartTime(new Date());
        parkingSpace.setStatus(1);
        //修改数据库信息
        parkingSpaceMapper.update(parkingSpace);

        //推送更新的车位数据（改为AOP完成）
        return Result.newResult(parkingSpace);
    }

    @Override
    public int getCost(Integer id) {
        ParkingSpace parkingSpace = parkingSpaceMapper.findById(id);
        Date now = new Date();
        Date startTime = parkingSpace.getStartTime();
        int money = (int) ((now.getTime() - startTime.getTime()) / (60 * 1000));
        return money;
    }

    @Override
    public Result pay(Integer id, Integer money) {
        ParkingSpace parkingSpace = parkingSpaceMapper.findById(id);
        Date now = new Date();
        Date startTime = parkingSpace.getStartTime();
        int payMoney = (int) ((now.getTime() - startTime.getTime()) / (60 * 1000));
        if (money != null && payMoney == money) {
            parkingSpace.setLocked(false);
            parkingSpace.setStartTime(null);
            parkingSpace.setStatus(0);
            parkingSpaceMapper.update(parkingSpace);
            //推送更新的车位数据（改为AOP完成）
            return Result.newResult(parkingSpace);
        } else {
            return Result.newErrResult();
        }
    }

    //定时任务 内部类 预定60秒后
    private class ReserveTimerTask extends TimerTask {
        private Integer id;

        public ReserveTimerTask(Integer id) {
            this.id = id;
        }

        @Override
        public void run() {//预定到时间没有停车，解锁车位
            System.out.println("触发了定时任务，取消预定车位" + id);
            if (sessionMap.containsKey(id)) {
                HttpSession session = sessionMap.remove(id);
                session.removeAttribute("reserve");//去除session中的预定信息
            }
            Result result = unlock(id);//到时间解锁车位，这个方法的调用不会经过AOP增强，所以下面需要手动添加WebSocket推送
            try { //推送更新的车位数据
                ParkingSpace parkingSpace = (ParkingSpace) result.getRes();
                WebSocketClients.boardCast(objectMapper.writeValueAsString(parkingSpace));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Result reserve(Integer id) {//预定
        ParkingSpace parkingSpace = parkingSpaceMapper.findById(id);
        if (!parkingSpace.getLocked() && parkingSpace.getStatus() == 0) {
            synchronized (this) {//双重锁校验，防止两个客户端争抢预定到同一个车位
                parkingSpace = parkingSpaceMapper.findById(id);
                if (!parkingSpace.getLocked() && parkingSpace.getStatus() == 0) {
                    //修改车位状态
                    Date now = new Date();
                    parkingSpace.setLocked(true);
                    parkingSpace.setStartTime(new Date(now.getTime() + RESERVE_MINUTES * 60 * 1000));//预定1分钟
                    parkingSpace.setStatus(2);//2表示预定
                    parkingSpaceMapper.update(parkingSpace);
                    //推送更新的车位数据（改为AOP完成）
                    //启动定时任务
                    ReserveTimerTask timerTask = new ReserveTimerTask(id);
                    timerTaskMap.put(id, timerTask);
                    timer.schedule(timerTask, RESERVE_MINUTES * 60 * 1000);
                    return Result.newResult(parkingSpace);
                }
            }
        }
        return Result.newErrResult();
    }

    //定时任务2  内部类
    private class ReserveTimerTask2 extends TimerTask {
        private Integer id;

        public ReserveTimerTask2(Integer id) {
            this.id = id;
        }

        @Override
        public void run() {
            System.out.println("触发了定时任务2，取消预定车位冷却" + id);
            if (timerTask2Map.containsKey(id)) {
                timerTask2Map.remove(id);
            }
            Result result = unlock(id);//到时间解除车位预定冷却，这个方法的调用不会经过AOP增强，所以下面需要手动添加WebSocket推送
            try { //推送更新的车位数据
                ParkingSpace parkingSpace = (ParkingSpace) result.getRes();
                WebSocketClients.boardCast(objectMapper.writeValueAsString(parkingSpace));
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public Result reserveUnlock(Integer id) {//预定解锁
        if (timerTaskMap.containsKey(id)) {
            TimerTask timerTask = timerTaskMap.remove(id);
            timerTask.cancel();//取消预约定时任务
        }

        ParkingSpace parkingSpace = new ParkingSpace();
        parkingSpace.setId(id);
        parkingSpace.setLocked(false);//打开锁
        parkingSpace.setStartTime(null);
        parkingSpace.setStatus(2);//2表示车位还处于预定冷却状态，无法被别人预定
        parkingSpaceMapper.update(parkingSpace);

        ReserveTimerTask2 reserveTimerTask2 = new ReserveTimerTask2(id);
        timer.schedule(reserveTimerTask2, 30 * 1000);//30秒后不停车，解除冷却
        timerTask2Map.put(id, reserveTimerTask2);

        //推送更新的车位数据（改为AOP完成）
        return Result.newResult(parkingSpace);
    }

    @Override
    public Result unlock(Integer id) {//管理员解锁
        if (timerTaskMap.containsKey(id)) {
            TimerTask timerTask = timerTaskMap.remove(id);
            timerTask.cancel();//取消定时任务
        }

        ParkingSpace parkingSpace = new ParkingSpace();
        parkingSpace.setId(id);
        parkingSpace.setLocked(false);//打开锁
        parkingSpace.setStartTime(null);
        parkingSpace.setStatus(0);
        parkingSpaceMapper.update(parkingSpace);

        //推送更新的车位数据（改为AOP完成）
        return Result.newResult(parkingSpace);
    }

    @Override
    public Result lock(Integer id) {//预定解锁、管理员锁定
        ParkingSpace parkingSpace = new ParkingSpace();
        parkingSpace.setId(id);
        parkingSpace.setStartTime(new Date());
        parkingSpace.setLocked(true);
        parkingSpace.setStatus(3);//3：被管理员锁定
        parkingSpaceMapper.update(parkingSpace);

        //推送更新的车位数据（改为AOP完成）
        return Result.newResult(parkingSpace);
    }
}
